#include "PriorityList.h"

PriorityList::PriorityList()
{
    root = 0;
    count = 0;
    position = root;
}

void PriorityList::add(Screen* value, int priority)
{
    PriorityListNode* addNode = new PriorityListNode(value, priority, 0, 0);

    // Create first node if there is none defined.
    if (root == 0)
    {
        root = addNode;
        count++;
        return ;
    }

    PriorityListNode* currentNode = root;
    while (currentNode->getNext() != 0)
    {
        // Remove duplicate if detected, and continue with the intention
        // to add at the appropriate spot.
        if (isSame(currentNode, addNode))
        {
            PriorityListNode* next = currentNode->getNext();
            // Keep the existing value to replace the value passed as a
            // parameter
            //std::cout << "old: " << value << " new: " << currentNode->getValue() << std::endl;
            //delete value;
            //value = currentNode->getValue();
            //addNode->setValue(value);

            // Remove unneeded node and set next
            delete currentNode->getValue();
            remove(currentNode);
            currentNode = next;
            continue;
        }

        // If we have reached a point where the next element is of a
        // higher priority, we will add our node directly before it.
        if (currentNode->getNext()->getPriority() > priority)
        {
            insert(addNode, currentNode, currentNode->getNext());
            return ;
        }
        currentNode = currentNode->getNext();
    }
    // Add node at the end of the list, checking first with the current
    // end node to make sure we aren't adding a duplicate. (Since this
    // check is never otherwise performed for the last node due to the
    // setup of the the while loop.)
    if (!isSame(currentNode, addNode))
    {
        insert(addNode, currentNode, 0);
        return ;
    }
}

void PriorityList::print()
{
    PriorityListNode* currentNode = root;
    while (currentNode != 0)
    {
        std::cout << "[" << currentNode->getValue()->getName() << "]"
            << " p: " << currentNode->getPriority()
            << " val:" << currentNode->getValue()
            << " next:" << currentNode->getNext() << std::endl;
        currentNode = currentNode->getNext();
    }
    std::cout << "Count: " << size() << std::endl;
}

unsigned int PriorityList::size()
{
    return count;
}

// Check if the position pointer has an initialized value
bool PriorityList::hasNext()
{
    if (position != 0)
    {
        return true;
    }
    return false;
}

// The client should use hasNext() before getting a next value
Screen* PriorityList::getNext()
{
    PriorityListNode* ret = position;
    position = position->getNext();
    return ret->getValue();
}

void PriorityList::resetPosition()
{
    position = root;
}

bool PriorityList::contains(std::string screenName)
{
    // Run through list and compare the given screen name string to the screen
    // name that is associated with the node's screen.
    PriorityListNode* currentNode = root;
    while (currentNode != 0)
    {
        if (screenName.compare(currentNode->getValue()->getName()) == 0)
        {
            return true;    // The two strings are equal
        }
        currentNode = currentNode->getNext();
    }
    return false;
}

void PriorityList::insert(PriorityListNode* node, PriorityListNode* last, PriorityListNode* next)
{
    node->setLast(last);
    node->setNext(next);

    if (last != 0)
    {
        last->setNext(node);
    }
    if (next != 0)
    {
        next->setLast(node);
    }

    count++;
}

void PriorityList::remove(PriorityListNode* node)
{
    // Four cases: if node is the first, last, only element of the list.
    // Otherwise remove without problem.

    if (node->getLast() == 0 && node->getNext() == 0)
    {
        root = 0;
    }
    else if (node->getLast() == 0)
    {
        node->getNext()->setLast(0); // Next node set as first node
        root = node->getNext();
    }
    else if (node->getNext() == 0)
    {
        node->getLast()->setNext(0); // Next node set as last node
    }
    else
    {
        node->getLast()->setNext(node->getNext()); // Last node set to next node
        node->getNext()->setLast(node->getLast()); // Next node set to last node
    }

    // Node is no longer needed
    delete node;

    count--;
}

// Compares values (not node last/next location) of two nodes, and also
// the unique name that each Scene has. We do not want two of the same
// scene type in the collection.
bool PriorityList::isSame(PriorityListNode* n1, PriorityListNode* n2)
{
    if (n1->getValue() == n2->getValue() ||
        n1->getValue()->getName().compare(n2->getValue()->getName()) == 0)
    {
        return true;
    }
    return false;
}
